#pragma once
// #define OS_USE_TPHUGEPAGE
#include <dbg.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
// #include <stdio.h>
#ifndef PAGE_SIZE
	#define PAGE_SIZE (4096)
	#define PAGE_SHIFT (12)
#endif

#if (WORD_WIDTH == 64)
#define MIN_RESERVE_SIZE (1UL << 30)
#else
#define MIN_RESERVE_SIZE (1UL << 24)
#endif

// #ifndef __USE_MISC
// #define __USE_MISC
// #endif
// #include <unistd.h>
// #include <stdio.h>
static inline void *__os_commit(void *ptr, unsigned long size, bool_t use_huge_page)
{
	void *mem = mmap(ptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
	if (UNLIKELY(mem == MAP_FAILED))
	{
		//perror("Error ");
		return NULL;
	}
	if(use_huge_page){
		int madv_ret = madvise(ptr, size, MADV_HUGEPAGE);
		if (madv_ret)
			fprintf(stderr, "madvise failed %d\n", madv_ret);
	}
	return mem;
}


static inline void *os_commit(void *ptr, unsigned long size)
{
	return __os_commit(ptr, size, 0);
}

static inline int os_decommit(void *ptr, unsigned long size)
{

	return munmap(ptr, size);
}

static inline int os_decommit_lazy(void *ptr, unsigned long size, bool_t lazy)
{
	if (lazy) return madvise(ptr, size, MADV_FREE);
	return os_decommit(ptr, size);
}
static inline int os_decommit_dontneed(void *ptr, unsigned long size)
{
	return madvise(ptr, size, MADV_DONTNEED);
}
static inline void *os_reserve_at_least(unsigned long size, unsigned long *size_get)
{

	unsigned long min_size = MIN_RESERVE_SIZE;
	unsigned long size_request = size > min_size ? size : min_size;
	void *p;

	for (; size_request >= size; size_request = size_request >> 1)
	{
		p = mmap(NULL, size_request, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

		if (p != MAP_FAILED)
		{

			//fprintf(stderr, "0x%lx-0x%lx, req_size %lx, real_get %lx\n", p, (unsigned long)p + size_request, size, size_request);
			*size_get = size_request;
			return p;
		}
	}
	return NULL;
}

static inline void *os_reserve_at_least_atheap(unsigned long size, unsigned long max_size, unsigned long *size_get, void *heap_ptr, bool_t huge_page)
{

	unsigned long size_request = size > max_size ? size : max_size;
	void *p;
	void *ptr = heap_ptr;
	for (; size_request >= size; size_request = size_request >> 1)
	{

		p = mmap(ptr, size_request, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
		if (p != MAP_FAILED)
		{
			INFO("%p-%p, req_size %lx, real_get %lx\n", p, p + size_request, size, size_request);
			if(huge_page){
				int madv_ret = madvise(ptr, size_request, MADV_HUGEPAGE);
				if (madv_ret)
					INFO("madvise failed %d\n", madv_ret);
			}
			*size_get = size_request;
			return p;
		}
	}
	// fprintf(stderr, "reserved failed\n");
	// abort();
	return NULL;
}
static inline void *os_get_heapstart()
{
	return (void *)MIN_RESERVE_SIZE;
}

static inline void *os_get_heapstart_offst(unsigned long offst)
{
	return (void *)offst;
}

static inline void *os_get_incrheap(void *heap_now, unsigned long size)
{
	if (0 != os_commit(heap_now, size))
	{
		return (void *)((unsigned long)heap_now + size);
	}
	return heap_now;
}